home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * Sockets routines to handle socket io of an objects. *
- * *
- * Written by: Gershon Elber Ver 0.1, June 1993. *
- *****************************************************************************/
-
- #include <stdio.h>
- #include <sys/types.h>
-
- #ifdef __UNIX__
- #if (defined(ultrix) && defined(mips)) || defined(_AIX) || defined(sgi)
- # include <fcntl.h>
- #else
- # include <sys/fcntl.h>
- #endif /* (ultrix && mips) || _AIX || sgi */
- #include <signal.h>
- #include <sys/socket.h>
- #if defined(__hpux) || defined(sun)
- # include <sys/file.h>
- #endif /* __hpux || sun */
- #include <netinet/in.h>
- #include <netdb.h>
- #endif /* __UNIX__ */
-
- #ifdef __WINNT__
- #include <stdlib.h>
- #include <windows.h>
- #include <winsock.h>
- #include <io.h>
- #endif /* __WINNT__ */
-
- #ifdef AMIGA
- #ifdef __SASC
- #include <dos.h>
- #endif
- #include <string.h>
- #include <exec/types.h>
- #include <exec/ports.h>
- #include <exec/memory.h>
- #include <dos/dostags.h>
- #include <proto/dos.h>
- #include <proto/exec.h>
- #endif /* AMIGA */
-
- #include "irit_sm.h"
- #include "prsr_loc.h"
- #include "irit_soc.h"
-
- #ifdef OS2GCC
- #define INCL_DOSPROCESS
- #include <os2.h>
- #endif /* OS2GCC */
-
- static void SocketPrintError(char *Str);
- #ifdef __UNIX__
- #if defined(_AIX) || defined(__hpux) || defined(sun)
- typedef void (*SignalFuncType)(int);
- #else
- typedef void (*SignalFuncType)(void);
- #endif /* _AIX || __hpux || sun */
- static void SocNoConnectionHandler(void);
- static void SocNoConnectionDummyHandler(void);
- #endif /* __UNIX__ */
-
- /*****************************************************************************
- * DESCRIPTION: *
- * IO error print routine. *
- * *
- * PARAMETERS: *
- * Str: To output to stderr as a message. *
- * *
- * RETURN VALUE: *
- * void *
- *****************************************************************************/
- static void SocketPrintError(char *Str)
- {
- # if defined(__UNIX__) || defined(OS2GCC) || defined(AMIGA)
- perror(Str);
- # endif /* __UNIX__ || OS2GCC */
- # ifdef __WINNT__
- fprintf(stderr, "iritserver: %s error %d\n", Str, WSAGetLastError());
- # endif /* __WINNT__ */
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Writes a single char to client's socket. M
- * *
- * PARAMETERS: M
- * Handler: The socket info handler index. M
- * c: Character to write. M
- * *
- * RETURN VALUE: M
- * void M
- * *
- * KEYWORDS: M
- * SocWriteChar, ipc M
- *****************************************************************************/
- void SocWriteChar(int Handler, char c)
- {
- #if defined(__UNIX__) || defined(__WINNT__)
- int i;
-
- if (_IPStream[Handler].CommuSoc <= 0) {
- IritPrsrFatalError("Attempt to write to a closed (broken!?) socket");
- return;
- }
-
- while ((i = send(_IPStream[Handler].CommuSoc, &c, 1, 0)) != 1) {
- if (i < 0) /* Lost connection probably. */
- SocServerCloseSocket(Handler);
- IritSleep(10);
- }
- #endif /* __UNIX__ || __WINNT__ */
- #ifdef OS2GCC
- ULONG BytesWritten;
- ULONG rc;
-
- rc = DosWrite(_IPStream[Handler].pipIrit, &c, 1, &BytesWritten);
- #endif /* OS2GCC */
- #ifdef AMIGA
- struct IritMessage msg;
-
- msg.msg.mn_Node.ln_Type = NT_MESSAGE;
- msg.msg.mn_ReplyPort = _IPStream[Handler].ReplySoc;
- msg.nbytes = 1;
- msg.txt[0] = c;
- msg.msg.mn_Length = sizeof(struct IritMessage) - LINE_LEN_LONG + msg.nbytes;
- PutMsg(_IPStream[Handler].CommuSoc, (struct Message *) &msg);
- WaitPort(_IPStream[Handler].ReplySoc);
- (void)GetMsg(_IPStream[Handler].ReplySoc);
- #endif /* AMIGA */
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Writes a single line of line length characters. M
- * *
- * PARAMETERS: M
- * Handler: The socket info handler index. M
- * Line: Line to write. M
- * LineLen: Length of line to write. M
- * *
- * RETURN VALUE: M
- * void M
- * *
- * KEYWORDS: M
- * SocWriteLine, ipc M
- *****************************************************************************/
- void SocWriteLine(int Handler, char *Line, int LineLen)
- {
- #if defined(__UNIX__) || defined(__WINNT__)
- int i;
-
- if (_IPStream[Handler].CommuSoc <= 0) {
- IritPrsrFatalError("Attempt to write to a closed (broken!?) socket");
- return;
- }
-
- while ((i = send(_IPStream[Handler].CommuSoc, Line,
- LineLen, 0)) < LineLen) {
- if (i < 0) /* Lost connection probably. */
- SocServerCloseSocket(Handler);
- IritSleep(10);
- LineLen = LineLen - i;
- Line = &Line[i];
- }
- #endif /* __UNIX__ || __WINNT__ */
- #ifdef OS2GCC
- ULONG BytesWritten;
- ULONG rc;
-
- rc = DosWrite(_IPStream[Handler].pipIrit, Line,
- LineLen, &BytesWritten);
- #endif /* OS2GCC */
- #ifdef AMIGA
- struct IritMessage msg;
-
- msg.msg.mn_Node.ln_Type = NT_MESSAGE;
- msg.msg.mn_ReplyPort = _IPStream[Handler].ReplySoc;
- for ( ; LineLen>0; LineLen-=msg.nbytes, Line+=msg.nbytes) {
- msg.nbytes = (LineLen > LINE_LEN_LONG) ? LINE_LEN_LONG : LineLen;
- memcpy(msg.txt, Line, msg.nbytes);
- msg.msg.mn_Length =
- sizeof(struct IritMessage) - LINE_LEN_LONG + msg.nbytes;
- PutMsg(_IPStream[Handler].CommuSoc, (struct Message *) &msg);
- WaitPort(_IPStream[Handler].ReplySoc);
- GetMsg(_IPStream[Handler].ReplySoc);
- }
- #endif /* AMIGA */
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Creates a server socket. Returns handler if successful. Also sets the M
- * IRIT_SERVER_PORT environment variable to the allocated socket. M
- * *
- * PARAMETERS: M
- * BinaryIPC: Do we want to communicate text or binary? M
- * Read: Is this socket for read (TRUE) or write (FALSE). M
- * *
- * RETURN VALUE: M
- * int: Non negative handler if successful, -1 otherwise. M
- * *
- * KEYWORDS: M
- * SocServerCreateSocket, ipc M
- *****************************************************************************/
- int SocServerCreateSocket(int BinaryIPC, int Read)
- {
- int Handler;
- static char Line[LINE_LEN];
-
- #if defined(__UNIX__) || defined(__WINNT__)
- int i, s;
- struct sockaddr_in Sain;
-
- ZAP_MEM(&Sain, sizeof(struct sockaddr_in));
- Sain.sin_addr.s_addr = htonl(INADDR_ANY);
- Sain.sin_family = AF_INET;
- #endif /* __UNIX__ || __WINNT__ */
-
- #if defined(__UNIX__) || defined(__WINNT__)
- #ifdef __WINNT__
- {
- WSADATA WSAData;
-
- if ((s = WSAStartup(MAKEWORD(1, 1), &WSAData)) != 0 ||
- LOBYTE(WSAData.wVersion) != 1 ||
- HIBYTE(WSAData.wVersion) != 1) {
- fprintf(stderr, "iritserver: WSAStartup: error %d\n",
- WSAGetLastError());
- return -1;
- }
- }
- #endif
-
- /* Create the socket, make it nonblocking if Read, and bind. */
- if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- fprintf(stderr, "iritserver: socket");
- return -1;
- }
-
- if (Read) {
- #ifdef __UNIX__
- #ifdef __hpux
- if (fcntl(s, F_SETFL, O_NDELAY) < 0) {
- #else
- if (fcntl(s, F_SETFL, FNDELAY) < 0) {
- #endif /* __hpux */
- SocketPrintError("iritclient: fcntl");
- return -1;
- }
- #endif /* __UNIX__ */
- }
-
- Sain.sin_port = 0;
- if (bind(s, (struct sockaddr *) &Sain, sizeof(struct sockaddr_in)) < 0) {
- fprintf(stderr, "iritserver: bind");
- return -1;
- }
-
- if (listen(s, 5) < 0) {
- fprintf(stderr, "iritserver: listen");
- return -1;
- }
-
- i = sizeof(struct sockaddr_in);
- if (getsockname(s, (struct sockaddr *) &Sain, &i) < 0) {
- fprintf(stderr, "iritserver: getsockname");
- return -1;
- }
-
- sprintf(Line, "IRIT_SERVER_PORT=%d", Sain.sin_port);
- putenv(Line);
-
- #ifdef __UNIX__
- signal(SIGPIPE, (SignalFuncType) SocNoConnectionHandler);
- #endif /* __UNIX__ */
-
- Handler = IritPrsrOpenStreamFromSocket(0, FALSE, BinaryIPC);
- _IPStream[Handler].MasterSoc = s;
- #endif /* __UNIX__ || __WINNT__ */
-
- #ifdef OS2GCC
- static int
- PipeCount = 0;
- HPIPE pipIrit;
- ULONG rc;
-
- sprintf(Line, "\\pipe\\irit_%d", ++PipeCount);
-
- rc = DosCreateNPipe(Line,
- &pipIrit,
- NP_ACCESS_DUPLEX | NP_NOWRITEBEHIND,
- NP_WAIT | NP_TYPE_BYTE | NP_READMODE_BYTE | 1,
- IRIT_PIPE_BUFFER_SIZE,
- IRIT_PIPE_BUFFER_SIZE,
- 0);
-
- if (rc != 0) {
- fprintf(stderr,
- "DosCreateNPipe: error in creating %s\n", Line);
- return FALSE;
- }
-
- Handler = IritPrsrOpenStreamFromSocket(0, FALSE, BinaryIPC);
- _IPStream[Handler].pipIrit = pipIrit;
-
- sprintf(Line, "IRIT_SERVER_PORT=\\pipe\\irit_%d", PipeCount);
- putenv(Line);
- #endif /* OS2GCC */
- #ifdef AMIGA
- static int portno = 0;
- char *name;
-
- Handler = IritPrsrOpenStreamFromSocket(0, FALSE, BinaryIPC);
- _IPStream[Handler].CommuSoc = CreateMsgPort();
- if (_IPStream[Handler].CommuSoc) {
- name = malloc(16);
- sprintf(name, "IRIT%d", portno++);
- _IPStream[Handler].CommuSoc->mp_Node.ln_Name = name;
- _IPStream[Handler].CommuSoc->mp_Node.ln_Pri = 0;
- AddPort(_IPStream[Handler].CommuSoc);
- _IPStream[Handler].ReplySoc = CreateMsgPort();
- if (!_IPStream[Handler].ReplySoc) {
- RemPort(_IPStream[Handler].CommuSoc);
- DeleteMsgPort(_IPStream[Handler].CommuSoc);
- _IPStream[Handler].CommuSoc = NULL;
- return FALSE;
- }
- } else {
- return FALSE;
- }
- sprintf(Line, "IRIT_SERVER_PORT=%s", name);
- putenv(Line);
- #endif /* AMIGA */
-
- return Handler;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Accepts a client socket connection. M
- * This function blocks until a connection with a client is established. M
- * *
- * PARAMETERS: M
- * Handler: The socket info handler index. M
- * *
- * RETURN VALUE: M
- * int: TRUE if succesful, FALSE otherwise. M
- * *
- * KEYWORDS: M
- * SocServerAcceptConnection, ipc M
- *****************************************************************************/
- int SocServerAcceptConnection(int Handler)
- {
- #if defined(__UNIX__) || defined(__WINNT__)
- struct sockaddr_in ClientSain;
- int i = SOC_TIME_OUT,
- Len = sizeof(ClientSain);
-
- while (i-- > 0 &&
- (_IPStream[Handler].CommuSoc =
- accept(_IPStream[Handler].MasterSoc,
- (struct sockaddr *) &ClientSain, &Len)) < 0)
- IritSleep(10);
-
- return i > 0;
- #endif /* __UNIX__ || __WINNT__ */
- #ifdef OS2GCC
- ULONG rc;
-
- if ((rc = DosConnectNPipe(_IPStream[Handler].pipIrit)) != 0) {
- fprintf(stderr,
- "DosConnectNPipe: error in connection %s\n",
- getenv("IRIT_SERVER_PORT"));
- return FALSE;
- }
-
- _IPStream[Handler].CommuSoc = 1;
-
- return TRUE;
- #endif /* OS2GCC */
- #ifdef AMIGA
- int len = -1;
- char buf[4];
- static int timescalled = 0;
-
- timescalled++;
- buf[0] = '\0';
- if (timescalled % 2) {
- while (len < 0) {
- len = GetVar(CLIENT_VAR, buf, sizeof(buf), GVF_GLOBAL_ONLY);
- if (len < 0) {
- #ifdef __SASC
- chkabort();
- #endif
- Delay(50L);
- }
- }
- DeleteVar(CLIENT_VAR, GVF_GLOBAL_ONLY);
- }
- return TRUE;
- #endif
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Closes a server socket/connection. M
- * *
- * PARAMETERS: M
- * Handler: The socket info handler index. M
- * *
- * RETURN VALUE: M
- * void M
- * *
- * KEYWORDS: M
- * SocServerCloseSocket, ipc M
- *****************************************************************************/
- void SocServerCloseSocket(int Handler)
- {
- #ifndef AMIGA
- if (_IPStream[Handler].CommuSoc > 0) {
- #ifdef __UNIX__
- char Line[LINE_LEN];
-
- /* Force the system to realize that the connection is down. This is */
- /* a kluge to solve the time out problem that happens under unix. */
- IritSleep(1000);
- signal(SIGPIPE, (SignalFuncType) SocNoConnectionDummyHandler);
- send(_IPStream[Handler].CommuSoc, Line, LINE_LEN, 0);
-
- if (close(_IPStream[Handler].CommuSoc) != 0)
- SocketPrintError("iritserver: close");
- #endif /* __UNIX__ */
- #ifdef __WINNT__
- closesocket(_IPStream[Handler].CommuSoc);
- #endif /* __WINNT__ */
- #ifdef OS2GCC
- DosClose(_IPStream[Handler].pipIrit);
- #endif /* OS2GCC */
- }
- #else /* AMIGA */
- if (_IPStream[Handler].CommuSoc) {
- RemPort(_IPStream[Handler].CommuSoc);
- free(_IPStream[Handler].CommuSoc->mp_Node.ln_Name);
- _IPStream[Handler].CommuSoc->mp_Node.ln_Name = NULL;
- DeleteMsgPort(_IPStream[Handler].CommuSoc);
- _IPStream[Handler].CommuSoc = NULL;
- if (_IPStream[Handler].ReplySoc) {
- DeleteMsgPort(_IPStream[Handler].ReplySoc);
- }
- }
- #endif /* AMIGA */
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Returns TRUE if connection is alive and active. M
- * *
- * PARAMETERS: M
- * Handler: The socket info handler index. M
- * *
- * RETURN VALUE: M
- * int: TRUE if connection to client exists. M
- * *
- * KEYWORDS: M
- * SocServerActive, ipc M
- *****************************************************************************/
- int SocServerActive(int Handler)
- {
- #ifndef AMIGA
- return _IPStream[Handler].CommuSoc > 0;
- #else
- return _IPStream[Handler].CommuSoc != 0;
- #endif /* AMIGA */
- }
-
- #ifdef __UNIX__
- /*****************************************************************************
- * DESCRIPTION: *
- * Cleans the server socket in case of a broken pipe. *
- * *
- * PARAMETERS: *
- * None *
- * *
- * RETURN VALUE: *
- * void *
- *****************************************************************************/
- static void SocNoConnectionHandler(void)
- {
- signal(SIGPIPE, (SignalFuncType) SocNoConnectionHandler);
- _IPParserAbort(IP_ERR_SOCKET_BROKEN, "");
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Dummy handler. *
- * *
- * PARAMETERS: *
- * None *
- * *
- * RETURN VALUE: *
- * void *
- *****************************************************************************/
- static void SocNoConnectionDummyHandler(void)
- {
- }
- #endif /* __UNIX__ */
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Attempts to write an object to a socket. M
- * *
- * PARAMETERS: M
- * Handler: The socket info handler index. M
- * PObj: Object to write to the client's socket. M
- * *
- * RETURN VALUE: M
- * void M
- * *
- * KEYWORDS: M
- * SocWriteOneObject, ipc M
- *****************************************************************************/
- void SocWriteOneObject(int Handler, IPObjectStruct *PObj)
- {
- char *ErrorMsg;
-
- if (IP_IS_UNDEF_OBJ(PObj)) {
- fprintf(stderr, "Socket: Attempt to write an undefined object.\n");
- return;
- }
- if (IP_IS_POLY_OBJ(PObj) && PObj -> U.Pl == NULL) {
- fprintf(stderr, "Socket: Attempt to write an empty poly object.\n");
- return;
- }
-
- IritPrsrPutObjectToHandler(Handler, PObj);
-
- if (IritPrsrParseError(_IPStream[Handler].LineNum, &ErrorMsg)) {
- fprintf(stderr, "Socket: %s\n", ErrorMsg);
- }
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Executes the given program and connect to it io ports. M
- * *
- * PARAMETERS: M
- * Program: Name of program to execute. Name can be NULL, in which the M
- * user is prompt to execute the program manually. M
- * PrgmInput: A handler to the Program's input channel. M
- * PrgmOutput: A handler to the Program's output channel. M
- * IsBinary: If TRUE sets channels to binary, if FALSE channels are text. M
- * *
- * RETURN VALUE: M
- * int: TRUE, if succesful, FALSE otherwise. M
- * *
- * KEYWORDS: M
- * IritPrsrSrvrExecAndConnect M
- *****************************************************************************/
- int IritPrsrSrvrExecAndConnect(char *Program,
- int *PrgmInput,
- int *PrgmOutput,
- int IsBinary)
- {
- int Input, Output;
- char Line[LINE_LEN];
- IPObjectStruct *PObj;
- #ifdef AMIGA
- char buf[4];
-
- buf[0] = '\0';
- SetVar(SERVER_VAR, buf, -1, GVF_GLOBAL_ONLY);
- #endif
- if ((Input = SocServerCreateSocket(IsBinary, FALSE)) < 0)
- return FALSE;
-
- if (Program != NULL && strlen(Program) > 0) {
- #if defined(__UNIX__)
- char DisplayCommand[LINE_LEN];
-
- sprintf(DisplayCommand, "%s &", Program);
- if (system(DisplayCommand) < 0) {
- /* This, in fact, is not working since system does not return */
- /* error code of display device. */
- sprintf(Line, "system: Failed to fork \"%s\"\n", Program);
- IritPrsrFatalError(Line);
- return FALSE;
- }
- #else
- #if defined(__WINNT__) || defined(OS2GCC)
- char DisplayCommand[LINE_LEN];
-
- sprintf(DisplayCommand, "start %s", Program);
- system(DisplayCommand);
- #else
- #ifdef AMIGA
- int HaveDisplay;
- BPTR f;
-
- f = Open("*", MODE_OLDFILE);
- HaveDisplay = !SystemTags(Program, SYS_Input, NULL,
- SYS_Output, f,
- SYS_Asynch, TRUE,
- TAG_END);
- /* SystemTags will always return success for programs run
- asynchronously, so wait a bit and then check if the synchronization
- environment variable created by the client exists. If not, we
- probably failed to start the program.
- */
- Delay(150L);
- if (GetVar(CLIENT_VAR, buf, sizeof(buf), GVF_GLOBAL_ONLY) < 0) {
- HaveDisplay = FALSE;
- }
- if (!HaveDisplay){
- fprintf(stderr,
- "Irit: Startup your program - I am waiting...\n\nsetenv IRIT_SERVER_PORT %s\n\n",
- getenv("IRIT_SERVER_PORT"));
- }
- #endif /* AMIGA */
- #endif /* __WINNT__ || OS2GCC */
- #endif /* __UNIX__ || AMIGA */
- }
- else
- fprintf(stderr,
- "Irit: Startup your program - I am waiting...\n\nsetenv IRIT_SERVER_PORT %s\n\n",
- getenv("IRIT_SERVER_PORT"));
-
- if (!SocServerAcceptConnection(Input))
- return FALSE;
-
- /* Send on open channel the name of the port for the other direction. */
- if ((Output = SocServerCreateSocket(IsBinary, TRUE)) < 0)
- return FALSE;
-
- sprintf(Line, "IRIT_SERVER_PORT=%s", getenv("IRIT_SERVER_PORT"));
- PObj = GenSTRObject(Line);
- SocWriteOneObject(Input, PObj);
- IPFreeObject(PObj);
-
- if (!SocServerAcceptConnection(Output))
- return FALSE;
-
- fprintf(stderr, "Connection established to \"%s\"\n",
- Program == NULL ? "?" : Program);
-
- *PrgmInput = Input;
- *PrgmOutput = Output;
-
- return TRUE;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Optionally kill and close channels to another process. M
- * *
- * PARAMETERS: M
- * Kill: If TRUE, send a KILL message to the other process. M
- * PrgmInput: A handler to the Program's input channel. M
- * PrgmOutput: A handler to the Program's output channel. M
- * *
- * RETURN VALUE: M
- * int: TRUE, if succesful, FALSE otherwise. M
- * *
- * KEYWORDS: M
- * IritPrsrSrvrKillAndDisConnect M
- *****************************************************************************/
- int IritPrsrSrvrKillAndDisConnect(int Kill, int PrgmInput, int PrgmOutput)
- {
- IPObjectStruct
- *PObj = GenStrObject("COMMAND_", Kill ? "EXIT" : "DISCONNECT", NULL);
-
- SocWriteOneObject(PrgmInput, PObj);
- IPFreeObject(PObj);
-
- SocServerCloseSocket(PrgmInput);
- SocServerCloseSocket(PrgmOutput);
-
- return TRUE;
- }
-
- #ifdef DEBUG_SERVER
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Simple test for the server - reads file and dumps one object every key. *
- *****************************************************************************/
- void main(int argc, char ** argv)
- {
- int Handler, PrgmInput, PrgmOutput;
- FILE
- *f = argc == 2 ? fopen(argv[1], "r") : stdin;
- IPObjectStruct *PObj,
- *PObjClear = IPAllocObject("_COMMAND_", IP_OBJ_STRING, NULL),
- *PObjs = IritPrsrGetObjects(f);
-
- if (argc == 2)
- fclose(f);
- strcpy(PObjClear -> U.Str, "CLEAR");
-
- Handler = IritPrsrSrvrExecAndConnect("x11drvs", &PrgmInput, &PrgmOutput,
- TRUE);
-
- while (TRUE) {
- for (PObj = PObjs; PObj != NULL; PObj = PObj -> Pnext) {
- fprintf(stderr, "Press return to send data.\n");
- getchar();
- SocWriteOneObject(Handler, PObj);
- }
-
- fprintf(stderr, "Done. Press return to send clear.\n");
- getchar();
- SocWriteOneObject(Handler, PObjClear);
- }
-
- IritPrsrSrvrKillAndDisConnect(TRUE, PrgmInput, PrgmOutput);
- }
-
- #endif /* DEBUG_SERVER */
-